#include "miio_command.h"
#include "json/jsmi.h"
#include "json/fmt.h"
#include "miio_user_api.h"
#include "mible_log.h"
#include "ble_spec/mi_spec_type.h"
#include "ble_spec/gatt_spec.h"
#include "common/mible_memory.h"

#if MI_LOCK_UART_ENABLE

#define MCMD_STR_LEN_MAX                    256
#define MCMD_SPEC_DATA_QUEUE_SIZE           8
#define MCMD_SPEC_OPERATION_TIMEOUT         3000
#define MCMD_SPEC_TIMER_TICKS               100
#define MCMD_SPEC_TIMEOUT_TICKS             (MCMD_SPEC_OPERATION_TIMEOUT/MCMD_SPEC_TIMER_TICKS)
#define ARRAY_SIZE(arr)                     (sizeof(arr) / sizeof((arr)[0]))

typedef struct {
    uint32_t    send_time;
    uint16_t    cmd;
    uint16_t    length;
    uint16_t    tid;
    char*       data;
} mcmd_spec_send_t;

static queue_t mcmd_spec_send_queue;
static mcmd_spec_send_t mcmd_spec_send_buf[MCMD_SPEC_DATA_QUEUE_SIZE];
static mcmd_spec_send_t s_mcmd_data;
static mcmd_spec_send_t *curr_mcmd_data = NULL;

extern mcmd_uart_t* mcmd_uart_host;
static void *m_rsp_timer = NULL;
static uint32_t mcmd_ticks = 0;

extern int gatt_send_properties_changed_internal(uint8_t nums, properties_t *newProps);
extern int gatt_send_event_occurred_internal(uint8_t siid, uint16_t eiid, arguments_t *newArgs);
int send_props_rsp_error(uint16_t cmd, char *data, uint16_t len);

static void rsp_timer_handler(void * p_context)
{
    //static uint64_t send_time = 0;
    mcmd_ticks++;
    
    if(curr_mcmd_data != NULL){
        //process timeout
        if(curr_mcmd_data->send_time + MCMD_SPEC_TIMEOUT_TICKS < mcmd_ticks){
            if(curr_mcmd_data->cmd == UART_CMD_SPEC_ACTION_IN){
                gatt_send_action_rsp(curr_mcmd_data->tid, OPERATION_ERROR_INNER, NULL);
            }else{
                send_props_rsp_error(curr_mcmd_data->cmd, curr_mcmd_data->data, curr_mcmd_data->length);
            }
            
            if(NULL != curr_mcmd_data->data){
                mible_free(curr_mcmd_data->data);
                curr_mcmd_data->data = NULL;
            }
            //clear curr data
            curr_mcmd_data = NULL;
        }
    }else{
        if (dequeue(&mcmd_spec_send_queue, &s_mcmd_data) == MI_ERR_NOT_FOUND){
            miio_timer_stop(m_rsp_timer);
            return;
        }
        curr_mcmd_data = &s_mcmd_data;
        curr_mcmd_data->send_time = mcmd_ticks;
        mcmd_uart_send(mcmd_uart_host, curr_mcmd_data->cmd, curr_mcmd_data->data, curr_mcmd_data->length);
    }
}

int mcmd_spec_init(void)
{
    if(NULL == m_rsp_timer){
        miio_timer_create(&m_rsp_timer, rsp_timer_handler, MIBLE_TIMER_REPEATED);
    }
    
    //init mi_spec_send_queue
    queue_init(&mcmd_spec_send_queue, (void*) mcmd_spec_send_buf, ARRAY_SIZE(mcmd_spec_send_buf), sizeof(mcmd_spec_send_buf[0]));
    mcmd_ticks = 0;
    
    return 0;
}

static mible_status_t sent_rsp_enque(uint16_t cmd, uint16_t tid, char* data, uint16_t len)
{
    mcmd_spec_send_t mcmd_data;
    mcmd_data.cmd = cmd;
    mcmd_data.tid = tid;
    mcmd_data.length = len;
    mcmd_data.data = data;
    mcmd_data.send_time = 0xFFFFFFFF;
    
    if(enqueue(&mcmd_spec_send_queue, &mcmd_data) == MI_ERR_NO_MEM){
        MI_LOG_ERROR("mcmd_spec_send_queue full.  %s:%d\n", (uint32_t)__FILE__, __LINE__);
        //mible_free(data);
        return MI_ERR_RESOURCES;
    }
    
    MI_LOG_DEBUG("send_data_enque OK.\n");
    return  MI_SUCCESS;
}

int jsmi_get_value_bytype(jsmi_parser_t parser, const jsmitok_t *parent, const char *key,
    property_value_t *value, uint16_t *value_type)
{
    int ret = 0;
    switch(value->format){
    case PROPERTY_FORMAT_NUMBER:{
        int32_t int_value;
        ret = jsmi_get_value_int32(parser, parent, key, &int_value);
        memcpy((char *)&value->data.number.integerValue, (char *)&int_value, sizeof(int_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_INT32 << 12) + 4;
    }break;
    case PROPERTY_FORMAT_BOOL:{
        bool bool_value;
        ret = jsmi_get_value_bool(parser, parent, key, &bool_value);
        memcpy((char *)&value->data.boolean, (char *)&bool_value, sizeof(bool_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_BOOL << 12) + 1;
    }break;
    case PROPERTY_FORMAT_FLOAT:{
        double value_double;
        ret = jsmi_get_value_double(parser, parent, key, &value_double);
        memcpy((char *)&value->data.number.floatValue, (char *)&value_double, sizeof(float));
        *value_type = (MIBLE_GATT_SPEC_TYPE_FLOAT << 12) + 4;
    }break;
    case PROPERTY_FORMAT_STRING:{
        if(value->data.string.value == NULL){
            MI_LOG_ERROR("Invalid string buffer\n");
            ret = MI_ERR_INVALID_PARAM;
            break;
        }
        memset(value->data.string.value, 0, value->data.string.length);
        ret = jsmi_get_value_str(parser, parent, key, value->data.string.value, value->data.string.length);
        value->data.string.length = strlen(value->data.string.value);
        *value_type = (MIBLE_GATT_SPEC_TYPE_STRING << 12) + value->data.string.length;
    }break;
    case PROPERTY_FORMAT_UCHAR:{
        uint8_t uchar_value;
        ret = jsmi_get_value_uint8(parser, parent, key, &uchar_value);
        memcpy((char *)&value->data.number.ucharValue, (char *)&uchar_value, sizeof(uchar_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_UINT8 << 12) + 1;
    }break;
    case PROPERTY_FORMAT_CHAR:{
        int8_t char_value;
        ret = jsmi_get_value_int8(parser, parent, key, &char_value);
        memcpy((char *)&value->data.number.charValue, (char *)&char_value, sizeof(char_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_INT8 << 12) + 1;
    }break;
    case PROPERTY_FORMAT_USHORT:{
        uint16_t ushort_value;
        ret = jsmi_get_value_uint16(parser, parent, key, &ushort_value);
        memcpy((char *)&value->data.number.ushortValue, (char *)&ushort_value, sizeof(ushort_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_UINT16 << 12) + 2;
    }break;
    case PROPERTY_FORMAT_SHORT:{
        int16_t short_value;
        ret = jsmi_get_value_int16(parser, parent, key, &short_value);
        memcpy((char *)&value->data.number.shortValue, (char *)&short_value, sizeof(short_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_INT16 << 12) + 2;
    }break;
    case PROPERTY_FORMAT_ULONG:{
        uint32_t ulong_value;
        ret = jsmi_get_value_uint32(parser, parent, key, &ulong_value);
        memcpy((char *)&value->data.number.ulongValue, (char *)&ulong_value, sizeof(ulong_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_UINT32 << 12) + 4;
    }break;
    case PROPERTY_FORMAT_LONG:{
        int32_t long_value;
        ret = jsmi_get_value_int32(parser, parent, key, &long_value);
        memcpy((char *)&value->data.number.longValue, (char *)&long_value, sizeof(long_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_INT32 << 12) + 4;
    }break;
    case PROPERTY_FORMAT_ULONGLONG:{
        uint64_t ulonglong_value;
        ret = jsmi_get_value_uint64(parser, parent, key, &ulonglong_value);
        memcpy((char *)&value->data.number.ulonglongValue, (char *)&ulonglong_value, sizeof(ulonglong_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_UINT64 << 12) + 8;
    }break;
    case PROPERTY_FORMAT_LONGLONG:{
        int64_t longlong_value;
        ret = jsmi_get_value_int64(parser, parent, key, &longlong_value);
        memcpy((char *)&value->data.number.longlongValue, (char *)&longlong_value, sizeof(longlong_value));
        *value_type = (MIBLE_GATT_SPEC_TYPE_INT64 << 12) + 8;
    }break;
    default:
        MI_LOG_ERROR("Invalid type\n");
        ret = MI_ERR_INVALID_PARAM;
    }
    return ret;
}

int jsmi_set_value_bytype(jsmi_composer_t composer, const char *key, gatt_spec_property_t *props, bool has_more)
{
    int ret = 0;
    
    switch(props->value_type >> 12)
    {
    case MIBLE_GATT_SPEC_TYPE_BOOL:{
        bool s_bool = 0;
        memcpy(&s_bool, props->value, 1);
        ret = jsmi_set_key_value_bool(composer, key, s_bool, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_UINT8:{
        uint8_t s_uchar;
        memcpy(&s_uchar, props->value, 1);
        ret = jsmi_set_key_value_uint8(composer, key, s_uchar, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_INT8:{
        int8_t s_char;
        memcpy(&s_char, props->value, 1);
        ret = jsmi_set_key_value_int8(composer, key, s_char, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_UINT16:{
        uint16_t s_ushort;
        memcpy(&s_ushort, props->value, 2);
        ret = jsmi_set_key_value_uint16(composer, key, s_ushort, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_INT16:{
        int16_t s_short;
        memcpy(&s_short, props->value, 2);
        ret = jsmi_set_key_value_int16(composer, key, s_short, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_UINT32:{
        uint32_t s_ulong;
        memcpy(&s_ulong, props->value, 4);
        ret = jsmi_set_key_value_uint32(composer, key, s_ulong, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_INT32:{
        int32_t s_long;
        memcpy(&s_long, props->value, 4);
        ret = jsmi_set_key_value_int32(composer, key, s_long, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_UINT64:{
        uint64_t s_ulonglong;
        memcpy(&s_ulonglong, props->value, 8);
        ret = jsmi_set_key_value_uint64(composer, key, s_ulonglong, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_INT64:{
        int64_t s_longlong;
        memcpy(&s_longlong, props->value, 8);
        ret = jsmi_set_key_value_int64(composer, key, s_longlong, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_FLOAT:{
        float s_float;
        memcpy(&s_float, props->value, 4);
        double s_double = s_float;
        ret = jsmi_set_key_value_double(composer, key, s_double, has_more);
    }break;
    case MIBLE_GATT_SPEC_TYPE_STRING:{
        uint8_t str_buf[MCMD_STR_LEN_MAX] = {0};
        uint16_t str_len = (props->value_type & 0xfff) >= sizeof(str_buf)? 
                            sizeof(str_buf)-1 : props->value_type & 0xfff;
        memcpy(str_buf, props->value, str_len);
        ret = jsmi_set_key_value_str(composer, key, (const char*)str_buf, has_more);
    }break;
    default:
        MI_LOG_ERROR("Invalid type\n");
        ret = MI_ERR_INVALID_PARAM;
        break;
    }
    
    return ret;
}

int send_props_rsp_error(uint16_t cmd, char *data, uint16_t len)
{
    int ret = 0;
    jsmi_parser_t jsmi_parser = NULL;
    properties_t *newProps = NULL;
    
    MI_LOG_DEBUG("send_props_rsp_error cmd %04x, len %d, %s\n", cmd, len, data);
    
    do{
        //parse json in buffer
        jsmi_parser = jsmi_parser_create((const char *)data, len);
        const jsmitok_t *tok_parent = NULL;
        const jsmitok_t *tok_array = NULL;
        if(NULL == jsmi_parser){
             MI_LOG_ERROR("Cannot create parser\n");
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        uint16_t tid;
        if(0 != jsmi_get_value_uint16(jsmi_parser, NULL, "id", &tid)){
            MI_LOG_ERROR("Cannot parse tid\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        
        tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "params");
        if(NULL == tok_parent) {
            MI_LOG_ERROR("Cannot find params\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        uint8_t p_num = JSMI_TOKCHILDREN(tok_parent);
        
        //2. malloc props buffer
        newProps = mible_malloc(sizeof(properties_t)*p_num);
        if(NULL == newProps){
            MI_LOG_ERROR("malloc fail  %s:%d\n", (uint32_t)__FILE__, __LINE__);
            ret = MI_ERR_NO_MEM;
            break;
        }
        memset(newProps, 0, sizeof(properties_t)*p_num);
        //3. parse props
        for(int i=0; i<JSMI_TOKCHILDREN(tok_parent); i++){
            uint8_t     siid = 0;
            uint16_t    piid = 0;
            int16_t     code = OPERATION_ERROR_INNER;

            tok_array = jsmi_array_value(jsmi_parser, tok_parent, i);
            if (NULL == tok_array) {
                MI_LOG_ERROR("Cannot parse array\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_uint8(jsmi_parser, tok_array, "siid", &siid)){
                MI_LOG_ERROR("Cannot parse siid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "piid", &piid)){
                MI_LOG_ERROR("Cannot parse piid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            //3.1 parse siid & piid & code to buffer
            newProps[i].siid = siid;
            newProps[i].piid = piid;
            newProps[i].code = code;
        }

        //4. send response
        if(ret == MI_SUCCESS){
            if(cmd == UART_CMD_SPEC_SET)
                ret = gatt_send_set_rsp(tid, p_num, newProps);
            else if(cmd == UART_CMD_SPEC_GET)
                ret = gatt_send_get_rsp(tid, p_num, newProps);
        }
    }while(false);
    
    if(jsmi_parser != NULL)
        jsmi_parser_delete(jsmi_parser);
    if(newProps != NULL){
        MI_LOG_DEBUG("free props %p\n", newProps);
        mible_free(newProps);
    }
    
    return ret;
}

mible_status_t do_set_properties(uint8_t *pdata, uint16_t ilen, uint16_t tid)
{
    int ret = MI_SUCCESS;
    
    MI_LOG_DEBUG("mcmd: recv set_properties\n");
    MI_LOG_HEXDUMP(pdata, ilen);
    
    do{
        //3.1 exec set operation for every props
        uint16_t sidx = 0;
        uint8_t p_num = *pdata;
        sidx += sizeof(p_num);
        
        char *buffer = NULL;//[MCMD_STR_LEN_MAX] = {0};
        buffer = mible_malloc(MCMD_STR_LEN_MAX);
        if(buffer == NULL){
            ret = MI_ERR_NO_MEM;
            break;
        }
        memset(buffer, 0, MCMD_STR_LEN_MAX);
        
        jsmi_composer_t composer = jsmi_composer_create((char *)buffer, MCMD_STR_LEN_MAX);
        if(composer == NULL){
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        //{"id":123,"params":[{"siid":3,"piid":7,"value":3}, {"siid":3,"piid":8,"value":false}]}
        jsmi_set_object_begin(composer);
            jsmi_set_key_value_uint16(composer, "id", tid, 1);
            jsmi_set_key(composer, "params");
            jsmi_set_array_begin(composer);
            for(int i = 0; i < p_num; i++){
                //parse siid piid
                gatt_spec_property_t *props;
                
                props = (gatt_spec_property_t *)(pdata + sidx);
                sidx += (props->value_type & 0xFFF) + 5;
                MI_LOG_DEBUG("idx %d, siid %d, piid %d, type %d, len %d, value:\n", i,
                    props->siid, props->piid, props->value_type >> 12, props->value_type & 0xFFF);
                MI_LOG_HEXDUMP(props->value, props->value_type & 0xFFF);
                uint16_t format;
                if((props->value_type >> 12) == MIBLE_GATT_SPEC_TYPE_BOOL)
                    format = PROPERTY_FORMAT_BOOL;
                else if((props->value_type >> 12) == MIBLE_GATT_SPEC_TYPE_FLOAT)
                    format = PROPERTY_FORMAT_FLOAT;
                else if((props->value_type >> 12) == MIBLE_GATT_SPEC_TYPE_STRING)
                    format = PROPERTY_FORMAT_STRING;
                else
                    format = (props->value_type >> 12) + PROPERTY_FORMAT_UCHAR - MIBLE_GATT_SPEC_TYPE_UINT8;
                
                //parse json
                jsmi_set_object_begin(composer);
                    jsmi_set_key_value_uint8(composer, "siid", props->siid, 1);
                    jsmi_set_key_value_uint16(composer, "piid", props->piid, 1);
                    jsmi_set_key_value_uint16(composer, "type", format, 1);
                    jsmi_set_value_bytype(composer, "value", props, 0);
                jsmi_set_object_end(composer, (i<p_num-1)? 1:0);
            }
            jsmi_set_array_end(composer, 0);
        jsmi_set_object_end(composer, 0);

        //TODO: send to queue list & set timeout 3s
        //mcmd_uart_send(mcmd_uart_host, UART_CMD_SPEC_SET, (char *)buffer, composer->js_len);
        ret = sent_rsp_enque(UART_CMD_SPEC_SET, tid, (char *)buffer, composer->js_len);
        if(ret != MI_SUCCESS){
            send_props_rsp_error(UART_CMD_SPEC_SET, (char *)buffer, composer->js_len);
            mible_free(buffer);
        }else{
            //wait uart ack
            miio_timer_start(m_rsp_timer, MCMD_SPEC_TIMER_TICKS, NULL);
        }
        jsmi_composer_delete(composer);
        
    }while(false);

    return (mible_status_t)ret;
}

mible_status_t do_get_properties(uint8_t *pdata, uint16_t ilen, uint16_t tid)
{
    int ret = MI_SUCCESS;
    
    MI_LOG_DEBUG("mcmd: recv get_properties\n");
    MI_LOG_HEXDUMP(pdata, ilen);
    
    do{
        //3.1 exec get operation for every props
        uint16_t sidx = 0;
        uint8_t p_num = *pdata;
        sidx += sizeof(p_num);
        
        char *buffer = NULL;//[MCMD_STR_LEN_MAX] = {0};
        buffer = mible_malloc(MCMD_STR_LEN_MAX);
        if(buffer == NULL){
            ret = MI_ERR_NO_MEM;
            break;
        }
        memset(buffer, 0, MCMD_STR_LEN_MAX);
        
        jsmi_composer_t composer = jsmi_composer_create((char *)buffer, MCMD_STR_LEN_MAX);
        if(composer == NULL){
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        //{"id":123,"params":[{"siid":3,"piid":7}, {"siid":3,"piid":8}]}
        jsmi_set_object_begin(composer);
            jsmi_set_key_value_uint16(composer, "id", tid, 1);
            jsmi_set_key(composer, "params");
            jsmi_set_array_begin(composer);
            for(int i = 0; i < p_num; i++){
                //parse siid piid
                uint8_t siid;
                uint16_t piid;
                memcpy(&siid, pdata+sidx, sizeof(siid));
                sidx += sizeof(siid);
                memcpy(&piid, pdata+sidx, sizeof(piid));
                sidx += sizeof(piid);
                //parse json
                jsmi_set_object_begin(composer);
                    jsmi_set_key_value_uint8(composer, "siid", siid, 1);
                    jsmi_set_key_value_uint16(composer, "piid", piid, 0);
                jsmi_set_object_end(composer, (i<p_num-1)? 1:0);
            }
            jsmi_set_array_end(composer, 0);
        jsmi_set_object_end(composer, 0);

        //TODO: send to queue list & set timeout 3s
        //mcmd_uart_send(mcmd_uart_host, UART_CMD_SPEC_GET, (char *)buffer, composer->js_len);
        ret = sent_rsp_enque(UART_CMD_SPEC_GET, tid, (char *)buffer, composer->js_len);
        if(ret != MI_SUCCESS){
            send_props_rsp_error(UART_CMD_SPEC_GET, (char *)buffer, composer->js_len);
            mible_free(buffer);
        }else{
            //wait uart ack
            miio_timer_start(m_rsp_timer, MCMD_SPEC_TIMER_TICKS, NULL);
        }
        jsmi_composer_delete(composer);
        
    }while(false);

    return (mible_status_t)ret;
}

mible_status_t do_action(uint8_t *pdata, uint16_t ilen, uint16_t tid)
{
    int ret = MI_SUCCESS;
    
    MI_LOG_DEBUG("mcmd: recv action\n");
    MI_LOG_HEXDUMP(pdata, ilen);
    
    do{
        //3.1 exec action operation
        uint16_t sidx = 0;
        uint8_t siid = *(pdata);
        uint8_t aiid = *(pdata + 1);
        uint8_t in_num = *(pdata + 2);
        sidx += 3;
        
        char *buffer = NULL;//[MCMD_STR_LEN_MAX] = {0};
        buffer = mible_malloc(MCMD_STR_LEN_MAX);
        if(buffer == NULL){
            ret = MI_ERR_NO_MEM;
            break;
        }
        memset(buffer, 0, MCMD_STR_LEN_MAX);
        
        jsmi_composer_t composer = jsmi_composer_create((char *)buffer, MCMD_STR_LEN_MAX);
        if(composer == NULL){
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        //{"id":123,"params":{"siid":2,"aiid":1,"in":[{"piid":1, "type":1,"value":false}]}}
        jsmi_set_object_begin(composer);
            jsmi_set_key_value_uint16(composer, "id", tid, 1);
            jsmi_set_key(composer, "params");
            jsmi_set_object_begin(composer);
                jsmi_set_key_value_uint8(composer, "siid", siid, 1);
                jsmi_set_key_value_uint8(composer, "aiid", aiid, 1);
                jsmi_set_key(composer, "in");
                jsmi_set_array_begin(composer);
                for(int i = 0; i < in_num; i++){
                    //parse piid & value, ignore siid
                    gatt_spec_property_t *props;
                    props = (gatt_spec_property_t *)(pdata + sidx - 1);
                    sidx += (props->value_type & 0xFFF) + 4;
                    uint16_t format;
                    if((props->value_type >> 12) == MIBLE_GATT_SPEC_TYPE_BOOL)
                        format = PROPERTY_FORMAT_BOOL;
                    else if((props->value_type >> 12) == MIBLE_GATT_SPEC_TYPE_FLOAT)
                        format = PROPERTY_FORMAT_FLOAT;
                    else if((props->value_type >> 12) == MIBLE_GATT_SPEC_TYPE_STRING)
                        format = PROPERTY_FORMAT_STRING;
                    else
                        format = (props->value_type >> 12) + PROPERTY_FORMAT_UCHAR - MIBLE_GATT_SPEC_TYPE_UINT8;
                    
                    jsmi_set_object_begin(composer);
                        jsmi_set_key_value_uint16(composer, "piid", props->piid, 1);
                        jsmi_set_key_value_uint16(composer, "type", format, 1);
                        jsmi_set_value_bytype(composer, "value", props, 0);
                    jsmi_set_object_end(composer, (i<in_num-1)? 1:0);
                }
                jsmi_set_array_end(composer, 0);
            jsmi_set_object_end(composer, 0);
        jsmi_set_object_end(composer, 0);

        //TODO: send to queue list & set timeout 3s
        //mcmd_uart_send(mcmd_uart_host, UART_CMD_SPEC_ACTION_IN, (char *)buffer, composer->js_len);
        ret = sent_rsp_enque(UART_CMD_SPEC_ACTION_IN, tid, (char *)buffer, composer->js_len);
        if(ret != MI_SUCCESS){
            gatt_send_action_rsp(tid, OPERATION_ERROR_INNER, NULL);
            mible_free(buffer);
        }else{
            //wait uart ack
            miio_timer_start(m_rsp_timer, MCMD_SPEC_TIMER_TICKS, NULL);
        }
        jsmi_composer_delete(composer);
        
    }while(false);

    return (mible_status_t)ret;
}

int cb_oncmd_spec_get_rsp(mcmd_uart_t* mcmd_uart, char *params, int length)
{
    int ret = MI_SUCCESS;
    unsigned char tmp_buff[MCMD_COMMAND_LEN_MAX] = {0};
    unsigned short v_length = 0; 
    unsigned char* p_length = NULL;
    jsmi_parser_t jsmi_parser = NULL;
    properties_t *newProps = NULL;

    if(NULL == mcmd_uart || NULL == params || length <= 0) {
        MI_LOG_ERROR("invalid params! %s:%d\n", (uint32_t)__FILE__, __LINE__);
        return MI_ERR_INVALID_PARAM;
    }
    p_length = (unsigned char *)&v_length;
    p_length[0] = params[9];
    p_length[1] = params[10];

    memcpy(tmp_buff, params + 11, v_length);
    MI_LOG_DEBUG("cb_oncmd_spec_get_rsp: %s, v_length= %d\n", tmp_buff, v_length);
    
    do{
        if(curr_mcmd_data == NULL || curr_mcmd_data->cmd != UART_CMD_SPEC_GET){
            ret = MI_ERR_INVALID_STATE;
            break;
        }
        
        //1. parse tid & get props num
        //{"id":123,"result":[{"siid":3, "piid":7, "code":0, "type":128, "value":3}, {"siid":3, "piid":8, "code":-4004}]}
        jsmi_parser = jsmi_parser_create((const char *)tmp_buff, v_length);
        const jsmitok_t *tok_parent = NULL;
        const jsmitok_t *tok_array = NULL;
        if(NULL == jsmi_parser){
            MI_LOG_ERROR("Cannot create parser\n");
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        uint16_t tid;
        if(0 != jsmi_get_value_uint16(jsmi_parser, NULL, "id", &tid)){
            MI_LOG_ERROR("Cannot parse tid\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        
        if(curr_mcmd_data->tid != tid){
            MI_LOG_ERROR("Cannot fetch tid last %d, now %d\n", curr_mcmd_data->tid, tid);
            ret = MI_ERR_INVALID_STATE;
            break;
        }
        
        tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "result");
        if(NULL == tok_parent) {
            MI_LOG_ERROR("Cannot find result\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        uint8_t p_num = JSMI_TOKCHILDREN(tok_parent);
        
        //2. malloc props buffer
        newProps = mible_malloc(sizeof(properties_t)*p_num);
        if(NULL == newProps){
            MI_LOG_ERROR("malloc fail  %s:%d\n", (uint32_t)__FILE__, __LINE__);
            ret = MI_ERR_NO_MEM;
            break;
        }
        memset(newProps, 0, sizeof(properties_t)*p_num);
        
        //3. parse props
        for(int i=0; i<JSMI_TOKCHILDREN(tok_parent); i++){
            uint8_t     siid;
            uint16_t    piid;
            int16_t     code;
            uint16_t    value_type;
            
            tok_array = jsmi_array_value(jsmi_parser, tok_parent, i);
            if (NULL == tok_array) {
                MI_LOG_ERROR("Cannot parse array\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_uint8(jsmi_parser, tok_array, "siid", &siid)){
                MI_LOG_ERROR("Cannot parse siid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "piid", &piid)){
                MI_LOG_ERROR("Cannot parse piid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_int16(jsmi_parser, tok_array, "code", &code)){
                MI_LOG_ERROR("Cannot parse code\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            //3.1 parse siid & piid & code to buffer
            newProps[i].siid = siid;
            newProps[i].piid = piid;
            newProps[i].code = code;
            
            //3.2 parse value to buffer
            if(code == 0){
                if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "type", &value_type)){
                    MI_LOG_ERROR("Cannot parse value_type\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                property_value_t value;
                char str_value[MCMD_STR_LEN_MAX];
                memset(&value, 0, sizeof(value));
                memset(&str_value, 0, sizeof(str_value));
                value.format = (property_format_t)value_type;
                if(value.format == PROPERTY_FORMAT_STRING){
                    value.data.string.value = str_value;
                    value.data.string.length = sizeof(str_value);
                }
                
                if(0 != jsmi_get_value_bytype(jsmi_parser, tok_array, "value", &value, &value_type)){
                    MI_LOG_ERROR("Cannot parse value\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                
                void *p_value = (value.format == PROPERTY_FORMAT_STRING)? (void*)str_value : (void*)&value.data;
                newProps[i].value = property_value_new_bytype(value.format, p_value, get_property_len(&value));
            }
        }//for(;;)
        
        //4. send response
        if(ret == MI_SUCCESS){
            ret = gatt_send_get_rsp(tid, p_num, newProps);
            if(ret == MI_SUCCESS && curr_mcmd_data->data != NULL){
                mible_free(curr_mcmd_data->data);
                curr_mcmd_data->data = NULL;
                curr_mcmd_data = NULL;
            }
        }
    }while(false);
    
    if(jsmi_parser != NULL)
        jsmi_parser_delete(jsmi_parser);
    if(newProps != NULL){
        MI_LOG_DEBUG("free get props %p\n", newProps);
        mible_free(newProps);
    }

    return ret;
}

int cb_oncmd_spec_set_rsp(mcmd_uart_t* mcmd_uart, char *params, int length)
{
    int ret = MI_SUCCESS;
    unsigned char tmp_buff[MCMD_COMMAND_LEN_MAX] = {0};
    unsigned short v_length = 0; 
    unsigned char* p_length = NULL;
    jsmi_parser_t jsmi_parser = NULL;
    properties_t *newProps = NULL;

    if(NULL == mcmd_uart || NULL == params || length <= 0) {
        MI_LOG_ERROR("invalid params! %s:%d\n", (uint32_t)__FILE__, __LINE__);
        return MI_ERR_INVALID_PARAM;
    }
    p_length = (unsigned char *)&v_length;
    p_length[0] = params[9];
    p_length[1] = params[10];

    memcpy(tmp_buff, params + 11, v_length);
    MI_LOG_DEBUG("cb_oncmd_spec_set_rsp: %s, v_length= %d\n", tmp_buff, v_length);
    
    do{
        if(curr_mcmd_data == NULL || curr_mcmd_data->cmd != UART_CMD_SPEC_SET){
            ret = MI_ERR_INVALID_STATE;
            break;
        }
        
        //1. parse tid & get props num
        //{"id":123,"result":[{"siid":3,"piid":7,"code":0}, {"siid":3,"piid":8,"code":-4004}]}
        jsmi_parser = jsmi_parser_create((const char *)tmp_buff, v_length);
        const jsmitok_t *tok_parent = NULL;
        const jsmitok_t *tok_array = NULL;
        if(NULL == jsmi_parser){
             MI_LOG_ERROR("Cannot create parser\n");
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        uint16_t tid;
        if(0 != jsmi_get_value_uint16(jsmi_parser, NULL, "id", &tid)){
            MI_LOG_ERROR("Cannot parse tid\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        
        if(curr_mcmd_data->tid != tid){
            MI_LOG_ERROR("Cannot fetch tid last %d, now %d\n", curr_mcmd_data->tid, tid);
            ret = MI_ERR_INVALID_STATE;
            break;
        }
        
        tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "result");
        if(NULL == tok_parent) {
            MI_LOG_ERROR("Cannot find result\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        uint8_t p_num = JSMI_TOKCHILDREN(tok_parent);
        
        //2. malloc props buffer
        newProps = mible_malloc(sizeof(properties_t)*p_num);
        if(NULL == newProps){
            MI_LOG_ERROR("malloc fail  %s:%d\n", (uint32_t)__FILE__, __LINE__);
            ret = MI_ERR_NO_MEM;
            break;
        }
        memset(newProps, 0, sizeof(properties_t)*p_num);
        
        //3. parse props
        for(int i=0; i<JSMI_TOKCHILDREN(tok_parent); i++){
            uint8_t     siid;
            uint16_t    piid;
            int16_t     code;
            
            tok_array = jsmi_array_value(jsmi_parser, tok_parent, i);
            if (NULL == tok_array) {
                MI_LOG_ERROR("Cannot parse array\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_uint8(jsmi_parser, tok_array, "siid", &siid)){
                MI_LOG_ERROR("Cannot parse siid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "piid", &piid)){
                MI_LOG_ERROR("Cannot parse piid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_int16(jsmi_parser, tok_array, "code", &code)){
                MI_LOG_ERROR("Cannot parse code\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            newProps[i].siid = siid;
            newProps[i].piid = piid;
            newProps[i].code = code;
        }//for(;;)
        
        //4. send response
        if(ret == MI_SUCCESS){
            ret = gatt_send_set_rsp(tid, p_num, newProps);
            if(ret == MI_SUCCESS && curr_mcmd_data->data != NULL){
                mible_free(curr_mcmd_data->data);
                curr_mcmd_data->data = NULL;
                curr_mcmd_data = NULL;
            }
        }
        
    }while(false);

    if(jsmi_parser != NULL)
        jsmi_parser_delete(jsmi_parser);
    if(newProps != NULL){
        MI_LOG_DEBUG("free set props %p\n", newProps);
        mible_free(newProps);
    }
    
    return MI_SUCCESS;
}

int cb_oncmd_spec_action_out(mcmd_uart_t* mcmd_uart, char *params, int length)
{
    int ret = MI_SUCCESS;
    unsigned char tmp_buff[MCMD_COMMAND_LEN_MAX] = {0};
    unsigned short v_length = 0; 
    unsigned char* p_length = NULL;
    jsmi_parser_t jsmi_parser = NULL;

    if(NULL == mcmd_uart || NULL == params || length <= 0) {
        MI_LOG_ERROR("invalid params! %s:%d\n", (uint32_t)__FILE__, __LINE__);
        return MI_ERR_INVALID_PARAM;
    }
    p_length = (unsigned char *)&v_length;
    p_length[0] = params[9];
    p_length[1] = params[10];

    memcpy(tmp_buff, params + 11, v_length);
    MI_LOG_DEBUG("cb_oncmd_spec_action_out: %s, v_length= %d\n", tmp_buff, v_length);
    
    do{
        if(curr_mcmd_data == NULL || curr_mcmd_data->cmd != UART_CMD_SPEC_ACTION_IN){
            ret = MI_ERR_INVALID_STATE;
            break;
        }
        
        //1. parse tid
        //{"id":1,"result":{"code":0,out:[{"piid":2,"type":128,"value":3}]}}
        jsmi_parser = jsmi_parser_create((const char *)tmp_buff, v_length);
        const jsmitok_t *tok_parent = NULL;
        const jsmitok_t *tok_array = NULL;
        if(NULL == jsmi_parser){
            MI_LOG_ERROR("Cannot create parser\n");
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        uint16_t tid;
        if(0 != jsmi_get_value_uint16(jsmi_parser, NULL, "id", &tid)){
            MI_LOG_ERROR("Cannot parse tid\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        
        if(curr_mcmd_data->tid != tid){
            MI_LOG_ERROR("Cannot fetch tid last %d, now %d\n", curr_mcmd_data->tid, tid);
            ret = MI_ERR_INVALID_STATE;
            break;
        }
        
        tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "result");
        if(NULL == tok_parent) {
            MI_LOG_ERROR("Cannot find result\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        
        //2. parse code
        int16_t code;
        if(0 != jsmi_get_value_int16(jsmi_parser, tok_parent, "code", &code)){
            MI_LOG_ERROR("Cannot parse code\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }

        arguments_t out_args;
        memset(&out_args, 0, sizeof(out_args));
        
        //3. parse out argument
        if(code == 0){
            tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "out");
            if(NULL == tok_parent) {
                MI_LOG_ERROR("Cannot find out\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            out_args.size = JSMI_TOKCHILDREN(tok_parent);
            if(out_args.size >= MAX_ARGUMENTS){
                MI_LOG_ERROR("arguments exceed the limit\n");
                ret = MI_ERR_NO_MEM;
                break;
            }
            
            //3. parse props
            for(int i=0; i<out_args.size; i++){
                uint16_t piid;
                uint16_t value_type;
                property_value_t value;
                char str_value[MCMD_STR_LEN_MAX];
                
                memset(&value, 0, sizeof(value));
                memset(&str_value, 0, sizeof(str_value));
                
                tok_array = jsmi_array_value(jsmi_parser, tok_parent, i);
                if (NULL == tok_array) {
                    MI_LOG_ERROR("Cannot parse array\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                
                if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "piid", &piid)){
                    MI_LOG_ERROR("Cannot parse piid\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                
                if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "type", &value_type)){
                    MI_LOG_ERROR("Cannot parse value_type\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                
                value.format = (property_format_t)value_type;
                if(value.format == PROPERTY_FORMAT_STRING){
                    value.data.string.value = str_value;
                    value.data.string.length = sizeof(str_value);
                }
                
                if(0 != jsmi_get_value_bytype(jsmi_parser, tok_array, "value", &value, &value_type)){
                    MI_LOG_ERROR("Cannot parse value\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }

                void *p_value = (value.format == PROPERTY_FORMAT_STRING)? 
                        (void*)value.data.string.value : (void*)&value.data;
                out_args.arguments[i].piid = piid;
                out_args.arguments[i].value = 
                    property_value_new_bytype(value.format, p_value, value.data.string.length);
            }//for(;;)
        }
        
        //4. send response
        if(ret == MI_SUCCESS){
            ret = gatt_send_action_rsp(tid, code, &out_args);
            if(ret == MI_SUCCESS && curr_mcmd_data->data != NULL){
                mible_free(curr_mcmd_data->data);
                curr_mcmd_data->data = NULL;
                curr_mcmd_data = NULL;
            }
        }else{
            //free operation arguments
            MI_LOG_DEBUG("free action arguments size %d\n", out_args.size);
            for (int i = 0; i < out_args.size; ++i){
                if (out_args.arguments[i].value != NULL){
                    property_value_delete(out_args.arguments[i].value);
                }
            }
        }
    }while(false);
    
    if(jsmi_parser != NULL)
        jsmi_parser_delete(jsmi_parser);

    return ret;
}

int cb_oncmd_spec_props_changed(mcmd_uart_t* mcmd_uart, char *params, int length)
{
    int ret = MI_SUCCESS;
    unsigned char tmp_buff[MCMD_COMMAND_LEN_MAX] = {0};
    unsigned short v_length = 0; 
    unsigned char* p_length = NULL;
    jsmi_parser_t jsmi_parser = NULL;
    properties_t *newProps = NULL;

    if(NULL == mcmd_uart || NULL == params || length <= 0) {
        MI_LOG_ERROR("invalid params! %s:%d\n", (uint32_t)__FILE__, __LINE__);
        return MI_ERR_INVALID_PARAM;
    }
    p_length = (unsigned char *)&v_length;
    p_length[0] = params[9];
    p_length[1] = params[10];

    memcpy(tmp_buff, params + 11, v_length);
    MI_LOG_DEBUG("cb_oncmd_spec_props_changed: %s, v_length= %d\n", tmp_buff, v_length);

    do{
        //1. get props num
        //{"id":123,"params":[{"siid":2,"piid":1, "type": 1, "value":false},{"siid":6,"piid":1, "type": 128, "value":1}]}
        jsmi_parser = jsmi_parser_create((const char *)tmp_buff, v_length);
        const jsmitok_t *tok_parent = NULL;
        const jsmitok_t *tok_array = NULL;
        if(NULL == jsmi_parser){
             MI_LOG_ERROR("Cannot create parser\n");
            ret = MI_ERR_NO_MEM;
            break;
        }
        
        tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "params");
        if(NULL == tok_parent) {
            MI_LOG_ERROR("Cannot find params\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        uint8_t p_num = JSMI_TOKCHILDREN(tok_parent);
        
        //2. malloc props buffer
        newProps = mible_malloc(sizeof(properties_t)*p_num);
        if(NULL == newProps){
            MI_LOG_ERROR("malloc fail  %s:%d\n", (uint32_t)__FILE__, __LINE__);
            ret = MI_ERR_NO_MEM;
            break;
        }
        memset(newProps, 0, sizeof(properties_t)*p_num);
        
        //3. parse props
        for(int i=0; i<JSMI_TOKCHILDREN(tok_parent); i++){
            uint8_t     siid;
            uint16_t    piid;
            uint16_t    value_type;
            
            tok_array = jsmi_array_value(jsmi_parser, tok_parent, i);
            if (NULL == tok_array) {
                MI_LOG_ERROR("Cannot parse array\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            //3.1 parse siid & piid to buffer
            if(0 != jsmi_get_value_uint8(jsmi_parser, tok_array, "siid", &siid)){
                MI_LOG_ERROR("Cannot parse siid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "piid", &piid)){
                MI_LOG_ERROR("Cannot parse piid\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            newProps[i].siid = siid;
            newProps[i].piid = piid;
            
            //3.2 parse value to buffer
            if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "type", &value_type)){
                MI_LOG_ERROR("Cannot parse value_type\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            property_value_t value;
            char str_value[MCMD_STR_LEN_MAX];
            memset(&value, 0, sizeof(value));
            memset(&str_value, 0, sizeof(str_value));
            value.format = (property_format_t)value_type;
            if(value.format == PROPERTY_FORMAT_STRING){
                value.data.string.value = str_value;
                value.data.string.length = sizeof(str_value);
            }
            
            if(0 != jsmi_get_value_bytype(jsmi_parser, tok_array, "value", &value, &value_type)){
                MI_LOG_ERROR("Cannot parse value\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            void *p_value = (value.format == PROPERTY_FORMAT_STRING)? (void*)str_value : (void*)&value.data;
            newProps[i].value = property_value_new_bytype(value.format, p_value, get_property_len(&value));
        }//for(;;)
        
        //4. send props changed
        if(ret == MI_SUCCESS){
            if(p_num == 1 && newProps[0].piid > 1000){  //gatt api don't release newProps, ble release
                ret = gatt_send_properties_changed_internal(p_num, newProps);
                if(ret != MI_SUCCESS) 
                    MI_LOG_ERROR("gatt_send_props fail %d\n", ret);
                ret = miio_ble_property_changed(newProps[0].siid, newProps[0].piid, newProps[0].value, 0);
            }else{                                      //gatt api release newProps
                ret = gatt_send_properties_changed(p_num, newProps);
            }
        }
    }while(false);
    
    if(jsmi_parser != NULL)
        jsmi_parser_delete(jsmi_parser);
    if(newProps != NULL){
        MI_LOG_DEBUG("free report props %p\n", newProps);
        mible_free(newProps);
    }
    
    return ret;
}

int cb_oncmd_spec_event_occured(mcmd_uart_t* mcmd_uart, char *params, int length)
{
    int ret = MI_SUCCESS;
    unsigned char tmp_buff[MCMD_COMMAND_LEN_MAX] = {0};
    unsigned short v_length = 0; 
    unsigned char* p_length = NULL;
    jsmi_parser_t jsmi_parser = NULL;

    if(NULL == mcmd_uart || NULL == params || length <= 0) {
        MI_LOG_ERROR("invalid params! %s:%d\n", (uint32_t)__FILE__, __LINE__);
        return MI_ERR_INVALID_PARAM;
    }
    p_length = (unsigned char *)&v_length;
    p_length[0] = params[9];
    p_length[1] = params[10];

    memcpy(tmp_buff, params + 11, v_length);
    MI_LOG_DEBUG("cb_oncmd_spec_event_occured: %s, v_length= %d\n", tmp_buff, v_length);
    
    do{
        //1. parse siid, eiid
        //{"id":123,"params":{"siid":2,"eiid":1,"arguments":
        //[{"piid":1, "type":1,"value":false}, {"piid":2, "type":128, "value":123}]}}
        jsmi_parser = jsmi_parser_create((const char *)tmp_buff, v_length);
        const jsmitok_t *tok_parent = NULL;
        const jsmitok_t *tok_array = NULL;
        if(NULL == jsmi_parser){
            MI_LOG_ERROR("Cannot create parser\n");
            ret = MI_ERR_NO_MEM;
            break;
        }

        tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "params");
        if(NULL == tok_parent) {
            MI_LOG_ERROR("Cannot find params\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }

        uint8_t siid;
        uint16_t eiid;
        uint16_t piid;
        uint16_t value_type;
        arguments_t * newArgs = NULL;
        
        if(0 != jsmi_get_value_uint8(jsmi_parser, tok_parent, "siid", &siid)){
            MI_LOG_ERROR("Cannot parse siid\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        
        if(0 != jsmi_get_value_uint16(jsmi_parser, tok_parent, "eiid", &eiid)){
            MI_LOG_ERROR("Cannot parse eiid\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        
        //2. parse arguments
        tok_parent = jsmi_key_value(jsmi_parser, tok_parent, "arguments");
        if(NULL == tok_parent) {
            MI_LOG_ERROR("Cannot find arguments\n");
            ret = MI_ERR_NOT_FOUND;
            break;
        }
        uint8_t p_num = JSMI_TOKCHILDREN(tok_parent);
        
        if(p_num){
            newArgs = arguments_new();
            if (newArgs == NULL){
                MI_LOG_ERROR("Cannot find result\n");
                ret = MI_ERR_NOT_FOUND;
                break;
            }
            
            //3. parse props
            for(int i=0; i<JSMI_TOKCHILDREN(tok_parent); i++){
                property_value_t value;
                char str_value[MCMD_STR_LEN_MAX];
                
                memset(&value, 0, sizeof(value));
                memset(&str_value, 0, sizeof(str_value));
                
                if(i >= MAX_ARGUMENTS){
                    MI_LOG_ERROR("arguments exceed the limit\n");
                    ret = MI_ERR_NO_MEM;
                    break;
                }
                
                tok_array = jsmi_array_value(jsmi_parser, tok_parent, i);
                if (NULL == tok_array) {
                    MI_LOG_ERROR("Cannot parse array\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                
                if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "piid", &piid)){
                    MI_LOG_ERROR("Cannot parse piid\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                
                if(0 != jsmi_get_value_uint16(jsmi_parser, tok_array, "type", &value_type)){
                    MI_LOG_ERROR("Cannot parse value_type\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }
                
                value.format = (property_format_t)value_type;
                if(value.format == PROPERTY_FORMAT_STRING){
                    value.data.string.value = str_value;
                    value.data.string.length = sizeof(str_value);
                }
                
                if(0 != jsmi_get_value_bytype(jsmi_parser, tok_array, "value", &value, &value_type)){
                    MI_LOG_ERROR("Cannot parse value\n");
                    ret = MI_ERR_NOT_FOUND;
                    break;
                }

                void *p_value = (value.format == PROPERTY_FORMAT_STRING)? 
                        (void*)value.data.string.value : (void*)&value.data;
                newArgs->arguments[i].piid = piid;
                newArgs->arguments[i].value = 
                    property_value_new_bytype(value.format, p_value, value.data.string.length);
            }
        }
        
        //4. send event
        if(ret == MI_SUCCESS){
            newArgs->size = p_num;
            if(eiid > 1000){  //gatt api don't release newArgs, ble release
                ret = gatt_send_event_occurred_internal(siid, eiid, newArgs);
                if(ret != MI_SUCCESS) 
                    MI_LOG_ERROR("gatt_send_event fail %d\n", ret);
                ret = miio_ble_event_occurred(siid, eiid, newArgs, 1);
            }else{            //gatt api release newArgs
                ret = gatt_send_event_occurred(siid, eiid, newArgs);
            }
        }else{
            arguments_delete(newArgs);
        }
    }while(false);

    if(jsmi_parser != NULL)
        jsmi_parser_delete(jsmi_parser);
    
    return MI_SUCCESS;
}

#endif //#if MI_LOCK_UART_ENABLE
